﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using yq.IBase.DBHelper;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using System.Linq.Expressions;
using cn.Util;

namespace yq.IBase.Basis
{
    /// <summary>
    /// 并行查询对象
    /// </summary>
    public class CutSelectBase<T> : SelectBase<T> where T : CutModelBase<T>, new()
    {
        private T tinfo=null;

        public CutSelectBase(T t)
        {
            tinfo = t;
        }

        private string TempTableName
        {
            get
            {
                return currentT.GetTableNameByCut(tinfo);
            }
        }

        private IList<string> TempTableNameList
        {
            get
            {
                return currentT.GetTableNameByCut();
            }
        }

        #region SQL分页语句并行查询，table名用{0}标记。
        
        /// <summary>
        /// SQL语句查询，table名用{0}标记。
        /// 将自动取出所有切割表迭代查询
        /// 并行的查询结果顺序可能变化
        /// </summary>
        /// <param name="sql">语句</param>
        /// <param name="page">分页对象</param>
        /// <param name="cn"></param>
        /// <param name="func">排序方式</param>
        /// <returns></returns>
        public PageList<T> WhereToPageList(string sql, PageModel page, DbHelper cn,Expression<Func<T, object>> func)
        {
            ordebyDic.Add(func,false);

            IList<string> tableList = new List<string>() { "sql" };
            if (sql.IndexOf("{0}") != -1)
            {
                //如果没有{0}标签说明不需要迭代表
                tableList = currentT.GetTableNameByCut();
            }

            PageList<T> outinfo = new PageList<T>();
            ConcurrentStack<IList<T>> data = new ConcurrentStack<IList<T>>();
            Parallel.ForEach(tableList, (table) =>
            {
                var strsql = string.Format(sql, table);
                data.Push(SQLToList(strsql, cn));
            });
            IList<T> list=new List<T>();
            while (data.TryPop(out list))
            {
                page.Count += list.Count;
                outinfo.AddRange(list);
                list = new List<T>();
            }

            return Paging(outinfo, page);
        }
       
        #endregion


        #region SQL语句并行查询，table名用{0}标记。

        /// <summary>
        /// SQL语句查询，table名用{0}标记。
        /// 将自动取出所有切割表迭代查询
        /// 并行的查询结果顺序可能变化
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="tableList">表名列表</param>
        /// <param name="cn"></param>
        /// <returns></returns>
        public IList<T> WhereToList(string sql, DbHelper cn)
        {
            IList<string> tableList = new List<string>() { "sql" };
            if (sql.IndexOf("{0}") != -1)
            {
                //如果没有{0}标签说明不需要迭代表
                tableList = currentT.GetTableNameByCut();
            }
            
            List<T> outinfo = new List<T>();
            ConcurrentStack<IList<T>> data = new ConcurrentStack<IList<T>>();
            Parallel.ForEach(tableList, (table) =>
            {
                var strsql = string.Format(sql, table);
                data.Push(SQLToList(strsql, cn));
            });
            IList<T> list;
            while (data.TryPop(out list))
            {
                outinfo.AddRange(list);
                list = new List<T>();
            }

            return outinfo;
        }

        private IList<T> SQLToList(string sql, DbHelper cn)
        {
            var comm = cn.GetSqlStringCommond(sql);
            var dt = cn.ExecuteDataTable(comm);
            return currentT.GetIList(dt);
        }

        #endregion


        #region 执行多条件查询的单表分页数据

        /// <summary>
        /// 执行多条件查询的单表分页数据
        /// </summary>
        /// <param name="func"></param>
        /// <param name="page"></param>
        /// <param name="cn"></param>
        /// <returns></returns>
        public override  PageList<T> ToPageList(PageModel page, DbHelper cn)
        {
            PageList<T> outinfo =new PageList<T>();
            if (tinfo != null)
            {
                outinfo = ToPageList(TempTableName, page, cn);
            }
            else
            {
                if (ordebyDic.Count == 0)
                {
                    throw new Exception("并行分页必须至少有一个orderby条件");
                }

                ConcurrentStack<IList<T>> data = new ConcurrentStack<IList<T>>();
                Parallel.ForEach(TempTableNameList, (table) =>
                {
                    data.Push(ToList(table, cn));
                });
                IList<T> list;
                while (data.TryPop(out list))
                {
                    page.Count += list.Count;
                    outinfo.AddRange(list);
                    list = new List<T>();
                }
                outinfo = Paging(outinfo, page);
            }
            return outinfo;
        }

        /// <summary>
        /// 用合并的PageList和PageModel 重新分页
        /// </summary>
        /// <param name="list"></param>
        /// <param name="page"></param>
        /// <returns></returns>
        private PageList<T> Paging(IList<T> list, PageModel page)
        {
            if (page.PageSize == 0)
            {
                throw new Exception("每页记录不能为0");
            }

            PageList<T> pagelist = new PageList<T>();
            var listOrder = new List<T>();

            //计算分页数量
            page.PageCount = page.Count / page.PageSize;

            if ((page.Count - page.PageCount * page.PageSize) > 0 || page.PageCount == 0)
            {
                page.PageCount++;
            }

            //如果超过分页页码
            if (page.PageIndex > page.PageCount)
            {
                page.PageIndex = page.PageCount;
            }

            foreach (var ordeby in ordebyDic)
            {
                var testc = ordeby.Key.Compile();

                if (ordeby.Value)
                {
                    listOrder = list.OrderByDescending(testc).ToList();
                }
                else
                {
                    listOrder = list.OrderBy(testc).ToList();
                }
            }

            
            int skip = page.PageSize * (page.PageIndex - 1);
            var plist=listOrder.Skip(skip).Take(page.PageSize);
            foreach (var info in plist)
            {
                pagelist.Add(info);
            }
            pagelist.PagerModel = page;

            return pagelist;
        }

        private PageList<T> ToPageList(string _tableName, PageModel page, DbHelper cn)
        {
            return new SelectBase<T>(this.whereList, this.ordebyDic, _tableName).ToPageList(page,cn);
        }
       
        #endregion


        #region 查询单表数据

        /// <summary>
        /// 查询单表数据 (配合多条件集合WherePlus使用)
        /// </summary>
        /// <param name="func"></param>
        /// <param name="cn"></param>
        /// <returns></returns>
        public override IList<T> ToList(DbHelper cn,int top=-1)
        {
            List<T> outinfo = new List<T>();
            if (tinfo != null)
            {
                return  ToList(TempTableName, cn);
            }
            else
            {
                ConcurrentStack<IList<T>> data = new ConcurrentStack<IList<T>>();
                Parallel.ForEach(TempTableNameList, (table) =>
                {
                    data.Push(ToList(table, cn));
                });
                IList<T> list;
                while (data.TryPop(out list))
                {
                    outinfo.AddRange(list);
                    list = new List<T>();
                }
            }

            return outinfo;
        }

        private IList<T> ToList(string _tableName, DbHelper cn)
        {
            return new SelectBase<T>(this.whereList, this.ordebyDic, _tableName).ToList(cn);
        }

        #endregion


        #region 查询单表符合条件的数量

        /// <summary>
        /// 查询单表符合条件的数量
        /// </summary>
        /// <param name="func"></param>
        /// <param name="cn"></param>
        /// <returns></returns>
        public override int ToCount(DbHelper cn)
        {
            int outinfo = 0;
            if (tinfo != null)
            {
                outinfo = ToCount(TempTableName, cn);
            }
            else
            {
                ConcurrentStack<int> data = new ConcurrentStack<int>();
                Parallel.ForEach(TempTableNameList, (table) =>
                {
                    data.Push(ToCount(table, cn));
                });
                int count = 0;
                while (data.TryPop(out count))
                {
                    outinfo += count;
                }
            }

            return outinfo;
        }

        private int ToCount(string _tableName, DbHelper cn)
        {
            return new SelectBase<T>(this.whereList, this.ordebyDic, _tableName).ToCount(cn);
        }
        #endregion


        #region 查询单表单条数据

        /// <summary>
        /// 查询单表单条数据
        /// </summary>
        /// <param name="func"></param>
        /// <param name="cn"></param>
        /// <returns></returns>
        public override T ToModel(DbHelper cn, RowLock rowLock = RowLock.Auto)
        {
            T outinfo=null;

            if(tinfo!=null)
            {
                outinfo = ToModel(TempTableName, cn, rowLock);
            }else
            {
                ConcurrentStack<T> data = new ConcurrentStack<T>();
                
                //并行查询
                Parallel.ForEach(TempTableNameList, (table) =>
                {
                   data.Push(ToModel(table, cn, rowLock));
                });
                while (data.TryPop(out outinfo))
                {
                    break;
                }
            }

            return outinfo;
        }

        private T ToModel(string _tableName, DbHelper cn, RowLock rowLock = RowLock.Auto)
        {
            return new SelectBase<T>(this.whereList, this.ordebyDic, _tableName).ToModel(cn, rowLock);
        }

        #endregion
    }
}
